package com.neu.utils;

import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Slf4j
@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 执行lua脚本
     *
     * @param script
     * @param keys
     * @param args
     * @return
     */
    public Object executeLuaScript(String script, List<String> keys, Object... args) {
        try {
            RedisScript<Object> redisScript = new DefaultRedisScript<>(script, Object.class); // 使用 DefaultRedisScript 封装脚本
            return redisTemplate.execute(redisScript, keys, args); // 执行脚本
        } catch (Exception e) {
            log.error("Redis执行Lua脚本失败", e);
            return null;
        }
    }

    //------------------字符串------------------

    /**
     * 设置键值对
     */
    public void set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            log.error("Redis设置值失败,key:{}", key, e);
        }
    }


    /**
     * 设置键值对并指定过期时间
     *
     * @param key     键
     * @param value
     * @param seconds 过期时间 单位秒
     */
    public void set(String key, Object value, long seconds) {
        try {
            redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("Redis设置值失败,key:{}", key, e);
        }
    }

    /**
     * 获取值
     *
     * @param key 键
     * @return Object
     */
    public Object get(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取值失败,key:{}", key, e);
            return null;
        }
    }

    /**
     * 从 Redis 获取值并反序列化为指定类型
     */
    public <T> T get(String key, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            if (clazz.isInstance(value)) {
                return clazz.cast(value);
            }
            return null;
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取值并反序列化失败,key:{}", key, e);
            return null;
        }
    }

    /**
     * 获取值
     *
     * @param key 键
     * @return String
     */
    public String getString(String key) {
        try {
            Object obj = redisTemplate.opsForValue().get(key);
            return obj == null ? null : obj.toString();
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取String值失败getString,key:{}", key, e);
            return null;
        }
    }

    /**
     * 删除键
     *
     * @param key 键
     * @return Boolean
     */
    public Boolean delete(String key) {
        try {
            return redisTemplate.delete(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis删除键失败delete,key:{}", key, e);
            return false;
        }
    }

    /**
     * 判断键是否存在
     *
     * @param key 键
     * @return Boolean
     */
    public Boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis判断键是否存在失败hasKey,key:{}", key, e);
            return false;
        }
    }

    /**
     * 如果不存在，则设置
     *
     * @param key   键
     * @param value 值
     * @return Boolean
     */
    public Boolean setNx(String key, Object value, long seconds) {
        try {
            return redisTemplate.opsForValue().setIfAbsent(key, value, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置值失败setNx,key:{}", key, e);
            return false;
        }
    }

    /**
     * 如果存在，则设置
     *
     * @param key
     * @param value
     * @param seconds
     * @return
     */
    public Boolean setEx(String key, Object value, long seconds) {
        try {
            return redisTemplate.opsForValue().setIfPresent(key, value, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置值失败setEx,key:{}", key, e);
            return false;
        }
    }

    /**
     * 自增
     *
     * @param key   键
     * @param delta 自增步长
     * @return Long
     */
    public Long increment(String key, long delta) {
        try {
            return redisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis自增失败increment,key:{}", key, e);
            return 0L;
        }
    }
    /**
     * 批量设置键值对
     * @param map
     * @param timeout
     * @param unit
     */
    public void batchSet(Map<String, String> map, long timeout, TimeUnit unit) {
        try {
            redisTemplate.executePipelined((RedisConnection connection) -> {
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    connection.set(entry.getKey().getBytes(), entry.getValue().getBytes());
                    connection.expire(entry.getKey().getBytes(), unit.toSeconds(timeout));
                }
                return null;
            });
        } catch (Exception e) {
            log.error("Redis批量设置键值对失败", e);
        }
    }
    /**
     * 批量删除键
     * @param keys
     */
    public void batchDelete(Collection<String> keys) {
        try {
            redisTemplate.executePipelined((RedisConnection connection) -> {
                for (String key : keys) {
                    connection.del(key.getBytes());
                }
                return null;
            });
        } catch (Exception e) {
            log.error("Redis批量删除键失败", e);
        }
    }
    //------------------哈希------------------

    /**
     * 设置哈希值
     *
     * @param key     键
     * @param hashKey 哈希键
     * @param value   值
     */
    public void hSet(String key, String hashKey, Object value) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置哈希值失败hSet,key:{}", key, e);
        }
    }

    /**
     * 设置哈希值并指定过期时间
     *
     * @param key     键
     * @param hashKey
     * @param value
     * @param seconds 过期时间 单位秒
     */
    public void hSet(String key, String hashKey, Object value, long seconds) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置哈希值失败hSet,key:{}", key, e);
        }
    }

    /**
     * 设置哈希键值对 putAll
     * 哈希（Hash）数据结构要求字段和值都是字符串。
     *
     * @param key 键
     * @param map 哈希键值对 Map<String, Object>
     */
    public void hSetAll(String key, Map<String, Object> map) {
        try {
            Map<String, String> stringMap = convertToStringMap(map);
            redisTemplate.opsForHash().putAll(key, stringMap);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置哈希键值对失败hSetAll,key:{}", key, e);
        }
    }

    private Map<String, String> convertToStringMap(Map<String, Object> originalMap) {
        Map<String, String> stringMap = new HashMap<>();
        for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
            stringMap.put(entry.getKey(), Convert.toStr(entry.getValue()));
        }
        return stringMap;
    }

    /**
     * 获取哈希值
     *
     * @param key     键
     * @param hashKey 哈希键
     * @return Object
     */
    public Object hGet(String key, String hashKey) {
        try {
            return redisTemplate.opsForHash().get(key, hashKey);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取哈希值失败hGet,key:{}", key, e);
            return null;
        }
    }

    /**
     * 获取哈希Map
     *
     * @param key 键
     * @return
     */
    public Map<Object, Object> hGetAll(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取哈希Map失败hGetAll,key:{}", key, e);
            return null;
        }
    }

    /**
     * 删除哈希键
     *
     * @param key     键
     * @param hashKey 哈希键 可以是多个
     * @return Long
     */
    public Long hDelete(String key, Object... hashKey) {
        try {
            return redisTemplate.opsForHash().delete(key, hashKey);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis删除哈希键失败hDelete,key:{}", key, e);
            return 0L;
        }
    }

    //------------------列表------------------

    /**
     * 从左边插入列表
     *
     * @param key   键
     * @param value 值
     * @return Long
     */
    public Long lLeftPush(String key, Object value) {
        try {
            return redisTemplate.opsForList().leftPush(key, value);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis从左边插入列表失败,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 从右边插入列表
     *
     * @param key   键
     * @param value 值
     * @return Long
     */
    public Long lRightPush(String key, Object value) {
        try {
            return redisTemplate.opsForList().rightPush(key, value);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis从右边插入列表失败,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 将一个集合插入到列表中
     *
     * @param key        键
     * @param collection 值 是集合
     * @return
     */
    public Long lRightPushAll(String key, Long expiration, Collection collection) {
        try {
            redisTemplate.opsForList().rightPushAll(key, collection);
            redisTemplate.expire(key, expiration, TimeUnit.SECONDS);
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis将一个集合插入到列表中失败lRightPushAll,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 从左边弹出列表
     *
     * @param key 键
     * @return Object
     */
    public Object lLeftPop(String key) {
        try {
            return redisTemplate.opsForList().leftPop(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis从左边弹出列表失败,key:{}", key, e);
            return null;
        }
    }

    /**
     * 从右边弹出列表
     *
     * @param key 键
     * @return Object
     */
    public Object lRightPop(String key) {
        try {
            return redisTemplate.opsForList().rightPop(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis从右边弹出列表失败,key:{}", key, e);
            return null;
        }
    }

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取list缓存的内容失败lRange,key:{}", key, e);
            // 返回一个空列表或默认值，也可以返回 null，取决于你的业务需求
            return Collections.emptyList();
        }
    }

    //------------------Set------------------

    /**
     * 添加元素
     *
     * @param key    键
     * @param values 值
     * @return Long
     */
    public Long sAdd(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis添加元素失败sAdd,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 根据键获取Set集合
     *
     * @param key 键
     * @return
     */
    public Set<Object> sMembers(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis根据键获取Set集合失败sMembers,key:{}", key, e);
            return Collections.emptySet();
        }
    }

    /**
     * 判断 member 元素是否是集合 key 的成员
     *
     * @param key    键
     * @param member 元素
     * @return Boolean
     */
    public Boolean sIsMember(String key, Object member) {
        try {
            return redisTemplate.opsForSet().isMember(key, member);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis判断 member 元素是否是集合 key 的成员失败sIsMember,key:{}", key, e);
            return false;
        }
    }

    /**
     * 移除元素
     *
     * @param key    键
     * @param values
     * @return
     */
    public Long sRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis移除元素失败sRemove,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 求交集
     *
     * @param key1 键1
     * @param key2 键2
     * @return
     */
    public Set<Object> sIntersect(String key1, String key2) {
        try {
            return redisTemplate.opsForSet().intersect(key1, key2);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis求交集失败sIntersect,key1:{},key2:{}", key1, key2, e);
            return Collections.emptySet();
        }
    }

    //------------------ZSet------------------

    /**
     * 添加元素
     *
     * @param key   大键
     * @param value 小键
     * @param score 分数
     * @return Boolean
     */
    public Boolean zAdd(String key, Object value, double score) {
        try {
            return redisTemplate.opsForZSet().add(key, value, score);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis添加元素失败zAdd,key:{}", key, e);
            return false;
        }
    }

    /**
     * 添加元素
     *
     * @param key    键
     * @param tuples 元素和分数的集合
     * @return Long
     */
    public Long zAdd(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        try {
            return redisTemplate.opsForZSet().add(key, tuples);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis添加元素失败zAdd,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 删除ZSet元素
     *
     * @param key    大键
     * @param values 小键
     * @return
     */
    public Long zRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForZSet().remove(key, values);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis删除ZSet元素失败zRemove,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 根据分数升序排序
     *
     * @param key   键
     * @param start 排名的最小值 0为第一名 分数最小
     * @param end   排名的最大值
     * @return [1, 2] 小键集合 按分数（或顺序）排序的后的列表
     */
    public Set<Object> zRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis根据分数升序排序失败zRange,key:{}", key, e);
            return Collections.emptySet();
        }
    }

    /**
     * 获取有序集合的元素及分数 升序
     *
     * @param key
     * @param start
     * @param end
     * @return {1=1.732963300535E12, 2=1.732963422243E12} 小键和分数的映射
     */
    public Map zRangeWithScore(String key, long start, long end) {
        try {
            Set<ZSetOperations.TypedTuple<Object>> tuple = redisTemplate.opsForZSet().rangeWithScores(key, start, end);
            Map map = new HashMap();
            for (ZSetOperations.TypedTuple<Object> objectTypedTuple : tuple) {
                map.put(objectTypedTuple.getValue(), objectTypedTuple.getScore());
            }
            return map;
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取有序集合的元素及分数失败zRangeWithScore,key:{}", key, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 根据分数降序排序
     *
     * @param key
     * @param start 排名的最小值 0为第一名 分数最大
     * @param end   排名的最大值
     * @return [1, 2] 小键集合 按分数（或顺序）排序的后的列表
     */
    public Set<Object> zReverseRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().reverseRange(key, start, end);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis根据分数降序排序失败zReverseRange,key:{}", key, e);
            return Collections.emptySet();
        }
    }

    /**
     * 获取有序集合的元素及分数 降序
     *
     * @param key
     * @param start
     * @param end
     * @return {1=1.732963300535E12, 2=1.732963422243E12} 小键和分数的映射
     */
    public Map zReverseRangeWithScore(String key, long start, long end) {
        try {
            Set<ZSetOperations.TypedTuple<Object>> tuple = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
            Map map = new HashMap();
            for (ZSetOperations.TypedTuple<Object> objectTypedTuple : tuple) {
                map.put(objectTypedTuple.getValue(), objectTypedTuple.getScore());
            }
            return map;
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取有序集合的元素及分数失败zReverseRangeWithScore,key:{}", key, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 最好是自己写一个分页查询，在这里封装数据类型给固定死了
     * 根据分数进行查询并且降序排序
     *
     * @param key
     * @param min    最小分数
     * @param max    最大分数
     * @param offset 偏移量 最小为0:从小于等于max的第一个开始（因为是降序）
     * @param count  查询个数
     * @return
     */
    public Map<Long, Long> zReverseRangeByScore(String key, long min, long max, long offset, long count) {
        try {
            Set<ZSetOperations.TypedTuple<Object>> tuple = redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max, offset, count);
            Map<Long, Long> map = new HashMap();
            for (ZSetOperations.TypedTuple<Object> objectTypedTuple : tuple) {
                map.put(Convert.toLong(objectTypedTuple.getValue()), Convert.toLong(objectTypedTuple.getScore()));
            }
            return map;
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis根据分数进行查询并且降序排序失败zReverseRangeByScore,key:{}", key, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 根据分数进行查询并且升序排序
     *
     * @param key
     * @param min    最小分数
     * @param max    最大分数
     * @param offset 偏移量 最小为0:从大于等于min的第一个开始（因为是升序）
     * @param count  查询个数
     * @return
     */
    public Map zRangeByScore(String key, long min, long max, long offset, long count) {
        try {
            Set<ZSetOperations.TypedTuple<Object>> tuple = redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, offset, count);
            Map map = new HashMap();
            for (ZSetOperations.TypedTuple<Object> objectTypedTuple : tuple) {
                map.put(objectTypedTuple.getValue(), objectTypedTuple.getScore());
            }
            return map;
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis根据分数进行查询并且升序排序失败zRangeByScore,key:{}", key, e);
            return Collections.emptyMap();
        }
    }


    /**
     * 获取元素的分数
     *
     * @param key   大键
     * @param value 小键
     * @return
     */
    public Double zgetScore(String key, Object value) {
        try {
            return redisTemplate.opsForZSet().score(key, value);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取元素的分数失败zgetScore,key:{}", key, e);
            return 0D;
        }
    }

    //-------------------GEO-------------------

    /**
     * 添加地理位置
     *
     * @param key       键
     * @param longitude double
     * @param latitude  double
     * @param member    地点标识 例如：地点名称/ID
     * @return
     */
    public Long geoAdd(String key, double longitude, double latitude, Long member) {
        try {
            Point point = new Point(longitude, latitude);
            return redisTemplate.opsForGeo().add(key, point, member);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis添加地理位置失败geoAdd,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 删除地理位置
     *
     * @param key     键
     * @param members 地点名称
     * @return
     */
    public Long geoRemove(String key, Long... members) {
        try {
            return redisTemplate.opsForGeo().remove(key, members);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis删除地理位置失败geoRemove,key:{}", key, e);
            return 0L;
        }
    }


    /**
     * 计算两个地理位置之间的距离
     *
     * @param key
     * @param member1 地点名称
     * @param member2 地点名称
     * @param metrics 单位 例如：Metrics.KILOMETERS
     * @return 返回Distance对象 包含距离和单位 拿不到返回null
     */
    public Distance geoDistance(String key, Long member1, Long member2, Metrics metrics) {
        try {
            return redisTemplate.opsForGeo().distance(key, member1, member2, metrics);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis计算两个地理位置之间的距离失败geoDistance,key:{}", key, e);
            return null;
        }
    }

    /**
     * @param key
     * @param longitude 圆心经度
     * @param latitude 圆心纬度
     * @param radius 半径
     * @param unit  单位
     * @return list中一个结果是下面这样·
     * GeoResult:
     *     content:RedisGeoCommands.GeoLocation(name=xizhan, point=Point [x=116.403963, y=39.915120])
     *         point:Point [x=116.403963, y=39.915120]
     *             x:116.40396326780319 //经度
     *             y:39.915120 //纬度
     *         name:xizhan
     *     distance:0.515 KILOMETERS
     *         value:0.515 //离圆心的距离
     *         unit:KILOMETERS
     */
    public List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> geoSearch(String key, double longitude, double latitude, double radius, Metrics unit) {
        try {
            Point point = new Point(longitude, latitude);
            Distance distance = new Distance(radius, unit);
            Circle circle = new Circle(point,distance); // 定义一个圆形范围
            RedisGeoCommands.GeoRadiusCommandArgs args =
                    RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                            .includeDistance()
                            .includeCoordinates()//在返回结果中包括距离和坐标信息
                            .sortAscending()
                            .limit(20);//指定返回结果应按距离升序排序，并且限制返回结果的数量
            // 执行 GEOSEARCH 查询，返回结果
            GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo().radius(key, circle, args);
            return results.getContent();
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis搜索附近地理位置失败geoSearch,key:{}", key, e);
            return Collections.emptyList();
        }
    }


    //-----------bitMap---------------
    /**
     * 设置位图
     *
     * @param key     键
     * @param offset  位图偏移量
     * @param value   位值
     * @return Boolean
     */
    public Boolean setBit(String key, long offset, boolean value) {
        try {
            return redisTemplate.opsForValue().setBit(key, offset, value);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis设置位图失败setBit,key:{}", key, e);
            return false;
        }
    }

    /**
     * 获取位图
     *
     * @param key    键
     * @param offset 位图偏移量
     * @return Boolean
     */
    public Boolean getBit(String key, long offset) {
        try {
            return redisTemplate.opsForValue().getBit(key, offset);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取位图失败getBit,key:{}", key, e);
            return false;
        }
    }

    /**
     * 获取指定范围的位
     * @param key  键
     * @param offset 位图偏移量 从位offset开始
     * @param length 位图长度 从位offset开始的length长度
     * @return
     */
    public List<Long> getBitField(String key, int offset, int length) {
        try {
            BitFieldSubCommands subCommand = BitFieldSubCommands.create()
                    .get(BitFieldSubCommands.BitFieldType.unsigned(length)).valueAt(offset); // 指定获取整数类型
            return redisTemplate.opsForValue().bitField(key, subCommand);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取指定范围的位失败getBitField,key:{}", key, e);
            return Collections.emptyList();
        }
    }


    //-----------------HyperLogLog-----------------
    /**
     * 添加元素到 HyperLogLog
     *
     * @param key    键
     * @param values 值
     * @return Long
     */
    public Long pfAdd(String key, Object... values) {
        try {
            return redisTemplate.opsForHyperLogLog().add(key, values);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis添加元素到 HyperLogLog失败pfAdd,key:{}", key, e);
            return 0L;
        }
    }

    /**
     * 获取 HyperLogLog 的基数
     *
     * @param key 键
     * @return Long
     */
    public Long pfCount(String key) {
        try {
            return redisTemplate.opsForHyperLogLog().size(key);
        } catch (Exception e) {
            // 使用日志框架记录异常信息
            log.error("Redis获取 HyperLogLog 的基数失败pfCount,key:{}", key, e);
            return 0L;
        }
    }

}
